package ts;

import java.util.Stack;
import java.util.Vector;

public class SymbolTable {

	private Stack<Scope> scope;
	private Vector<Info> lut;
	private Integer count;
	public static StringBuffer strTS;
	public static int errors;
	public SymbolTable() {
		strTS = new StringBuffer();
		this.scope = new Stack<Scope>();
		this.scope.push(new Scope());
		this.lut = new Vector<Info>();
		this.lut.add(new ModInfo(""));
		this.count = 1;
		errors = 0;
	}

	public void createScope() {
		scope.push(new Scope());
		//System.out.println("novo scopo nivel " + scope.size());
	}

	public void removeScope() {
		//System.out.println("remover scopo nivel " + scope.size());
		scope.pop();
	}

	public Integer insert(String id, Info info) {
		strTS.append("ID = " + id + "\tcategoria = " +info.getCategoria()+ "\tscopo = " + scope.size()
				+ "\tposicao = " + count + "\n");
		if (isInsertableAtCurrentScope(id)) {
			lut.add(info);
			scope.lastElement().insert(id, count);
			return count++;
		} else {
			System.out.println("ID: " + id
					+ " no escopo atual já foi declarada");
			errors++;
			return 0;
		}
		
	}

	public Integer lookup(String id) {
		Integer index = 0;
		int i = scope.size() - 1;
		while (index == 0 && i >= 0) {
			index = scope.elementAt(i).lookup(id);
			if (!(getInfo(index).getCategoria().equals("variable")) && !(getInfo(index).getCategoria().equals("parameter"))) {
				index = 0;
			}
			i--;
		}
		if (index == 0) {
			System.out.println("ID: " + id + " não foi declarado ou nao pode ser atribuido");
			errors++;
		}
		//else
		//	System.out.println("ID: " + id + " se encontra em " + index);
		return index;
	}
	
	public Integer lookupModule(String id) {
		Integer index = 0;
		int i = scope.size() - 1;
		while (index == 0 && i >= 0) {
			index = scope.elementAt(i).lookup(id);
			if (!(getInfo(index).getCategoria().equals("module"))) {
				index = 0;
			}
			i--;
		}
		if (index == 0) {
			System.out.println("ID: " + id + " não foi declarado");
			errors++;
		}
		//else
		//	System.out.println("ID: " + id + " se encontra em " + index);
		return index;
	}
	
	public Integer lookupProccall(String id) {
		Integer index = 0;
		int i = scope.size() - 1;
		while (index == 0 && i >= 0) {
			index = scope.elementAt(i).lookup(id);
			if (!(getInfo(index).getCategoria().equals("procedure")) && !(getInfo(index).getCategoria().equals("function"))) {
				index = 0;
			}
			i--;
		}
		if (index == 0) {
			System.out.println("Procedimento ou Funcao: " + id + " não foi declarado ou não é um método ou procedimento");
			errors++;
		}
		//else
		//	System.out.println("Procedimento ou Funcao: " + id + " se encontra em " + index);
		return index;
	}

	public Info getInfo(Integer index) {
		Info info = lut.elementAt(index);
		return info;
	}

	public Boolean isInsertableAtCurrentScope(String id) {
		if (scope.lastElement().lookup(id) == 0)
			return true;
		return false;
	}
}
